//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace WorkflowApplicationControls
{
    using Microsoft.Practices.Unity;
    using WorkflowApplication.Interfaces;
    using System.Windows;
    using System.Windows.Controls;
    using Microsoft.Research.DataLayer;
    using WorkflowApplicationModels;
    using System.Collections.ObjectModel;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using System;
    using Microsoft.Research.ScientificWorkflow.UIDesigner.WpfComposite;
    using WorkflowApplicationModels.Helpers;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.Research.eResearch.Common.Linq;
    using TM = Microsoft.Research.ScientificWorkflow.TridentModel;

    /// <summary>
    /// The presenter for the left pane.
    /// </summary>
    public class LeftPanePresenter : ILeftPanePresenter
    {
        #region Private Members

        /// <summary>
        /// The unity container.
        /// </summary>
        private IUnityContainer container;

        /// <summary>
        /// Service for registry access.
        /// </summary>
        private IRegistryService registryService;

        /// <summary>
        /// The collection of models.
        /// </summary>
        private ObservableCollection<BaseModel> leftPaneItems = new ObservableCollection<BaseModel>();

        #endregion Private Members

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="LeftPanePresenter"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="leftPane">The left pane.</param>
        /// <param name="service">The service.</param>
        public LeftPanePresenter(IUnityContainer container, WorkflowTree leftPane, IRegistryService service)
        {
            this.container = container;
            this.LeftPane = leftPane;
            this.LeftPane.DataContext = this;
            this.registryService = service;
        }

        #endregion Constructor

        #region Public Properties

        /// <summary>
        /// Gets or sets the left pane.
        /// </summary>
        /// <value>The left pane.</value>
        public UserControl LeftPane { get; set; }

        /// <summary>
        /// Gets the left pane items.
        /// </summary>
        /// <value>The left pane items.</value>
        public ObservableCollection<BaseModel> LeftPaneItems
        {
            get
            {
                return this.leftPaneItems;
            }
        }

        /// <summary>
        /// Gets or sets the item selected command.
        /// </summary>
        /// <value>The item selected command.</value>
        public WorkflowAppCommand<BaseModel> ItemSelectedCommand { get; set; }

        #endregion Public Properties

        #region Public Methods

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        public void Initialize()
        {
            this.PopulateTree();
        }

        /// <summary>
        /// Refreshes this instance.
        /// </summary>
        public bool Refresh(WorkflowModel currentModel)
        {
            bool prevWfPresent = false;
            Guid prevId = Guid.Empty;
            if (currentModel != null)
            {
                prevId = currentModel.Id;
            }

            this.PopulateTree();
            if (!prevId.Equals(Guid.Empty))
            {
                BaseModel model = BaseModel.GetModelById(prevId, this.LeftPaneItems);
                if (model != null)
                {
                    model.IsSelected = true;
                    prevWfPresent = true;
                }
            }

            return prevWfPresent;
        }

        #endregion Public Methods

        #region Private Methods

        private void PopulateTree()
        {
            try
            {
                this.LeftPaneItems.Clear();
                Collection<Namespace> categories = new Collection<Namespace>();
                this.registryService.GetWorkflowCategories(categories);
                categories.ForEach(category => category.Children.ForEach(child => this.LeftPaneItems.Add(new CategoryModel(child, this.registryService.FetchCurrentUser()))));
                categories.Clear();
                this.registryService.GetMyWorkflowsForCurrentUser(categories);
                categories.ForEach(category => this.LeftPaneItems.Add(new CategoryModel(category, this.registryService.FetchCurrentUser())));

                if (TridentAuthentication.LoggedUserRole == UserRole.Admin)
                {
                    categories.Clear();
                    this.registryService.GetAllUsersMyWorkflows(categories);
                    if (categories.Count > 0 && categories.Any(category => category.Activitys.Where(activity => !activity.IsDeleted).Count() > 0))
                    {
                        CategoryModel allUsersWorkflowsModel = CategoryModel.GenerateVirtualCategoryModel("All users' Workflows", new List<Activity>());
                        foreach (Namespace category in categories)
                        {
                            if (category.Activitys.Where(activity => !activity.IsDeleted).Count() > 0)
                            {
                                CategoryModel catModel = CategoryModel.GenerateVirtualCategoryModel((new TM.SecurityPrincipalModel(category.User as ISecurityPrincipal)).DisplayName, category.Activitys);
                                allUsersWorkflowsModel.Children.Add(catModel);
                            }
                        }

                        this.LeftPaneItems.Add(allUsersWorkflowsModel);
                    }
                }
                else if (TridentAuthentication.LoggedUserRole == UserRole.NormalUser || 
                    TridentAuthentication.LoggedUserRole == UserRole.Guest)
                {
                    ICollection<Activity> sharedWorkflows = this.registryService.GetAllSharedWorkflowsForCurrentUser();
                    if (sharedWorkflows != null && sharedWorkflows.Count > 0)
                    {
                        CategoryModel sharedWfsCategory = CategoryModel.GenerateVirtualCategoryModel("Shared Workflows", new List<Activity>());
                        var userGroupedWfs = from wf in sharedWorkflows
                                             group wf by (wf.Owner as IObject).ID into wfGroup
                                             select new
                                             {
                                                 SecurityPrincipal = new TM.SecurityPrincipalModel(wfGroup.ElementAt(0).Owner),
                                                 UserSharedWfs = wfGroup.Where(wf => this.CheckForActivity(wf))
                                             };

                        if (userGroupedWfs != null && userGroupedWfs.Count() > 0)
                        {
                            var groupedNonEmpty = userGroupedWfs.Where(userGrp => userGrp.UserSharedWfs != null && userGrp.UserSharedWfs.Count() > 0);
                            groupedNonEmpty.ForEach(
                                userGroup => sharedWfsCategory.Children.Add(
                                    CategoryModel.GenerateVirtualCategoryModel(userGroup.SecurityPrincipal.DisplayName, userGroup.UserSharedWfs)));
                        }

                        this.LeftPaneItems.Add(sharedWfsCategory);
                    }
                }
            }
            catch (TridentCustomException ex)
            {
                TridentErrorHandler.HandleTridentCustomExceptionInUI(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleKnownExceptionsInUI(ex);
            }
        }

        private bool CheckForActivity(Activity activity)
        {
            bool validActivity = false;
            if (!activity.IsDeleted
                && (!string.IsNullOrEmpty(activity.VersionLabel) || activity.IsLatestVersion())
                && activity.Namespaces[0].Name.Equals("My Workflow", StringComparison.OrdinalIgnoreCase)
                && activity.Namespaces[0].Parent.Name.Equals("UserWorkflowRoot", StringComparison.OrdinalIgnoreCase)
                && (activity.Security.Rights.RunWorkflow.Check(this.registryService.FetchCurrentUser())
                    || activity.Security.Rights.AuthorWorkflow.Check(this.registryService.FetchCurrentUser())))
            {
                validActivity = true;
            }

            return validActivity;
        }

        #endregion Private Methods
    }
}
